/* QtLua -- Lua bindings for Qt
   Copyright (C) 2011, Jarek Pelczar

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 3 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General
   Public License along with this library; if not, write to the
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301 USA

*/

#include "wrap_QPoint.h"
#include "qluascriptvalue.h"
#include "qluascriptcontext.h"
#include "qluaexception.h"
#include <QDebug>

QPoint_Prototype::QPoint_Prototype(QObject * parent)
    : QObject(parent)
{
}

QPoint * QPoint_Prototype::ptr() const
{
    QPoint * ptr = qtlua_scriptvalue_cast<QPoint>(thisObject());
    if(!ptr) {
        engine()->throwException(engine()->newException(QLatin1String("QPoint_prototype: Unable to cast this object to QPoint")));
    }
    return ptr;
}

bool QPoint_Prototype::isNull() const
{
    return ptr()->isNull();
}

int QPoint_Prototype::getX() const
{
    return ptr()->x();
}

int QPoint_Prototype::getY() const
{
    return ptr()->y();
}

void QPoint_Prototype::setX(int x)
{
    ptr()->setX(x);
}

void QPoint_Prototype::setY(int y)
{
    ptr()->setY(y);
}

int QPoint_Prototype::manhattanLength() const
{
    return ptr()->manhattanLength();
}

QPointF QPoint_Prototype::toPointF() const
{
    return QPointF(*ptr());
}

QPointF * QPointF_Prototype::ptr() const
{
    QPointF * ptr = qtlua_scriptvalue_cast<QPointF>(thisObject());
    if(!ptr) {
        engine()->throwException(engine()->newException(QLatin1String("QPointF_prototype: Unable to cast this object to QPointF")));
    }
    return ptr;
}

QPointF_Prototype::QPointF_Prototype(QObject * parent)
    : QObject(parent)
{
}

bool QPointF_Prototype::isNull() const
{
    return ptr()->isNull();
}

qreal QPointF_Prototype::getX() const
{
    return ptr()->x();
}

qreal QPointF_Prototype::getY() const
{
    return ptr()->y();
}

void QPointF_Prototype::setX(qreal x)
{
    ptr()->setX(x);
}

void QPointF_Prototype::setY(qreal y)
{
    ptr()->setY(y);
}

qreal QPointF_Prototype::manhattanLength() const
{
    return ptr()->manhattanLength();
}

QPoint QPointF_Prototype::toPoint() const
{
    return ptr()->toPoint();
}

QPoint_wrapper::QPoint_wrapper(QLuaScriptEngine * engine)
    : QObject(engine),
      QLuaScriptClass(engine)
{
    m_proto = engine->newQObject(new QPoint_Prototype(engine),
                                 QLuaScriptEngine::ScriptOwnership);

    engine->setGlobal("QPoint", engine->newQObject(this));
    engine->setGlobal("QPoint_prototype", m_proto);

    qluaRegisterScriptMetaType<QPoint>(engine,
                                       QPoint_toScriptValue,
                                       QPoint_fromScriptValue);
}

QPoint_wrapper::QueryFlags QPoint_wrapper::queryProperty(const QLuaScriptValue& object,
                                 const QByteArray& name)
{
    if(name == "newPoint") {
        return HandlesCallAccess;
    }

    return 0;
}

QLuaScriptValue QPoint_wrapper::property(const QLuaScriptValue& object,
                                      const QByteArray& name)
{
    if(name == "newPoint") {
        return scriptEngine()->newFunction(new_point);
    }

    return QLuaScriptValue();
}

QLuaScriptValue QPoint_wrapper::prototype() const
{
    return m_proto;
}

QString QPoint_wrapper::name() const
{
    return QLatin1String("QPoint");
}

QLuaScriptValue QPoint_wrapper::QPoint_toScriptValue(QLuaScriptEngine * engine, const QPoint * t)
{
    QLuaScriptValue value = engine->newUserDataWithGc<QPoint>(engine->getGlobal("QPoint_prototype"));
    QPoint * obj = qtlua_scriptvalue_cast<QPoint>(value);
    if(t)
        *obj = *t;
#ifdef QT_DEBUG
    qDebug() << "Create QPoint" << *obj;
#endif
    return value;
}

void QPoint_wrapper::QPoint_fromScriptValue(const QLuaScriptValue& value, QPoint * t)
{
    QPoint * scriptT = qtlua_scriptvalue_cast<QPoint>(value);
    if(scriptT) {
        *t = *scriptT;
    } else {
        qWarning("[QtLua] Trying to convert from another metatype of userdata to QPoint");
    }
}

QLuaScriptValue QPoint_wrapper::new_point(QLuaScriptContext * context, QLuaScriptEngine * engine)
{
    QLuaScriptValue value = engine->newUserDataWithGc<QPoint>(engine->getGlobal("QPoint_prototype"));
    QPoint * obj = qtlua_scriptvalue_cast<QPoint>(value);
    if(context->argumentCount() == 1)
    {
        if(QPoint * p2 = qtlua_scriptvalue_cast<QPoint>(context->argument(0))) {
            *obj = *p2;
        } else if(context->argument(0).isTable()) {
            obj->setX(context->argument(0).property("x").toInteger());
            obj->setY(context->argument(0).property("y").toInteger());
        }
    } else if(context->argumentCount() == 2) {
        obj->setX(context->argument(0).toInteger());
        obj->setY(context->argument(1).toInteger());
    }
    return value;
}

QPointF_wrapper::QPointF_wrapper(QLuaScriptEngine * engine)
    : QObject(engine),
      QLuaScriptClass(engine)
{
    m_proto = engine->newQObject(new QPointF_Prototype(engine),
                                 QLuaScriptEngine::ScriptOwnership);

    engine->setGlobal("QPointF", engine->newQObject(this));
    engine->setGlobal("QPointF_prototype", m_proto);

    qluaRegisterScriptMetaType<QPointF>(engine,
                                       QPointF_toScriptValue,
                                       QPointF_fromScriptValue);
}

QPointF_wrapper::QueryFlags QPointF_wrapper::queryProperty(const QLuaScriptValue& object,
                                 const QByteArray& name)
{
    if(name == "newPoint") {
        return HandlesCallAccess;
    }

    return 0;
}

QLuaScriptValue QPointF_wrapper::property(const QLuaScriptValue& object,
                                      const QByteArray& name)
{
    if(name == "newPoint") {
        return scriptEngine()->newFunction(new_pointF);
    }

    return QLuaScriptValue();
}

QLuaScriptValue QPointF_wrapper::prototype() const
{
    return m_proto;
}

QString QPointF_wrapper::name() const
{
    return QLatin1String("QPointF");
}

QLuaScriptValue QPointF_wrapper::QPointF_toScriptValue(QLuaScriptEngine * engine, const QPointF * t)
{
    QLuaScriptValue value = engine->newUserDataWithGc<QPointF>(engine->getGlobal("QPointF_prototype"));
    QPointF * obj = qtlua_scriptvalue_cast<QPointF>(value);
    if(t)
        *obj = *t;
#ifdef QT_DEBUG
    qDebug() << "Create QPointF" << *obj;
#endif

    return value;
}

void QPointF_wrapper::QPointF_fromScriptValue(const QLuaScriptValue& value, QPointF * t)
{
    QPointF * scriptT = qtlua_scriptvalue_cast<QPointF>(value);
    if(scriptT) {
        *t = *scriptT;
    } else {
        qWarning("[QtLua] Trying to convert from another metatype of userdata to QPointF");
    }
}

QLuaScriptValue QPointF_wrapper::new_pointF(QLuaScriptContext * context, QLuaScriptEngine * engine)
{
    QLuaScriptValue value = engine->newUserDataWithGc<QPointF>(engine->getGlobal("QPointF_prototype"));
    QPointF * obj = qtlua_scriptvalue_cast<QPointF>(value);
    if(context->argumentCount() == 1)
    {
        if(QPointF * p2 = qtlua_scriptvalue_cast<QPointF>(context->argument(0))) {
            *obj = *p2;
        } if(QPoint * p2 = qtlua_scriptvalue_cast<QPoint>(context->argument(0))) {
            *obj = *p2;
        } else if(context->argument(0).isTable()) {
            obj->setX(context->argument(0).property("x").toNumber());
            obj->setY(context->argument(0).property("y").toNumber());
        }
    } else if(context->argumentCount() == 2) {
        obj->setX(context->argument(0).toNumber());
        obj->setY(context->argument(1).toNumber());
    }
    return value;
}
